//=====©️ArenaPlus 侵权必究=====//
/*
                                          ~~~                                          
                                     ~~~~~~~~~~~~~                                     
                                 %%%%%%%%%%%%%%%%%%%%%                                 
                              %%%%%%%%%%%%%%%%%%%%%%%%%%%                              
                           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                          
                       %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
                    %%%%%%%%%%%%%%%%%%%%~~~~~~~~%%%%%%%%%%%%%%%%%%%%                   
                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                
             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            
         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%         
       ^^^^^^^^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^       
      ^^^^^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%~%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^     
     ^^^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^     
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
     &&&&&&&&&^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&^^^^^^^&&&^^^^^^^&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&&=======&&&&&&&&========&&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&&&&&&&&&&&&&&&&&&&=========================&&&&&&&&&&&&&&&&&&&&&&&&&&    
     &&&&&&&&&===========================================================&&&&&&&&&&    
     ==============================================================================    
     =========================       ==============        ========================    
     ========================        ===============       ========================    
     ========================       =================       =======================    
     ========================      ===================     ========================    
     =============                                                    =============    
      ===============     &%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   ================     
       =================&%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%================      
                      =^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                    
                    =&~~~~~%&&&&&&~~&&&&&&&&&`%&&&&&~~&&&&&^~`~^&&&&&                  
                  ===```~~````===~``%=======~``&===&``~==%``%&^```=====                
                     ```   ^``^  ~``^       ~``=   &``~  ~``%=                         
                     `````````   ~``&       ~``=   =``~    &~`````                     
                     ```         ~``%       &``=   =``^   %     ```                    
                     ``~         ^```````%   &```````%    ```````` 
*/
//=====©️ArenaPlus 侵权必究=====//

//--------摔伤函数-------//
/**
 * 摔伤函数，在代码中调用一次，即开启衰落
 * 使用要求：选择器得到的结果必须是玩家实体且保证不再在代码中使用player.fall玩家实体附属变量
 * 
 * @param {string} entityKind 玩家实体选择器，如"player"、".*"、"#"
 */

global.fallPlayer = async function (entityKind) {
    while (true) {
        world.querySelectorAll(entityKind).forEach(async (/** @type {GamePlayerEntity} @param {entity} 受到衰落检查的玩家实体 */entity) => {
            if (!entity.isPlayer) {
                console.error('fallPlayer()---Error: 玩家实体选择器错误，当前选择器：' + entityKind)
                return;
            }
            entity.enableDamage = true
            switch (entity.player.moveState) {
                case GamePlayerMoveState.FALL:
                    if (!entity.player.fall) { entity.player.fall = 0 }
                    entity.player.fall += Math.random()
                    break;
            }
            entity.onVoxelContact(({ entity }) => {
                if (entity.player.fall < 8) {
                    entity.player.fall = 0;
                    return;
                }
                entity.player.directMessage('[剩余HP：' + entity.hp + ']你受到了' + entity.player.fall + '点摔伤伤害')
                entity.hurt(entity.player.fall)
                entity.player.fall = 0
                if (!entity.hp) {
                    world.say(`${entity.player.name}摔，卒`)
                }
            });
        });
        await sleep(60)
    }
}
//--------摔伤函数-------//

//--------跑酷速用-------//

/**
 * 跑酷速用函数，包含碰到什么(方块)会死亡，碰到什么(模型实体)会存档
 * 
 * @param {string} entityIdStarts 模型实体id的前缀部分，例如存档点实体的id可以是'存档点-1'，此处填'存档点'
 * @param {string|number} blockId 碰到会导致死亡的方块名称
 * @param {string} [saveMessage] 到达存档点时的玩家消息提示，不写则默认为“存档成功！”
 * @param {string} [deadMessage] 玩家实体死亡时的玩家消息提示，不写则默认为无
 * 
 */
global.parkour = async function (entityIdStarts, blockId, { saveMessage, deadMessage }) {
    for (const e of world.querySelectorAll('*')) {//遍历所有实体
        if (e.id.startsWith(entityIdStarts)) {//如果当前实体名左边部分刚好是"存档点", 比如 存档点-1 存档点-2...
            e.collides = true //开启碰撞
            e.fixed = true //固定实体不被推移
            e.onEntityContact(async ({ other }) => { //每当存档点碰到另一个实体
                if (other.isPlayer) { //另一个实体是玩家
                    if (e.position !== other.player.spawnPoint) { // 检测当前存档点是否玩家重生点, 避免反复在同一个存档点做多余的保存
                        if (saveMessage) {
                            other.player.directMessage(saveMessage) // 给玩家发消息
                        } else {
                            other.player.directMessage('存档成功！') // 给玩家发消息
                        }
                        other.player.spawnPoint = e.position // 把玩家重生点坐标设置成存档点的坐标
                    }
                }
            })
        }
    }

    world.onVoxelContact(({ entity, voxel }) => {
        if (!entity.isPlayer) return
        if (voxel === voxels.id(blockId)) {
            entity.position.copy(entity.player.spawnPoint)
            entity.position.y += 4
        }
        if (deadMessage) {
            entity.player.directMessage(deadMessage)
        }
    })
}
//--------跑酷速用-------//

//--------加入退出--------//

/**
 * 玩家加入游戏时，world.say()提示
 */
global.join = function () {
    world.onPlayerJoin(async ({ entity }) => {
        world.say(entity.player.name + ' 加入了游戏');
    })
}

/**
 * 玩家退出游戏时，world.say()提示
 */
global.leave = function () {
    world.onPlayerLeave(async ({ entity }) => {
        world.say(entity.player.name + ' 退出了游戏');
    })
}

//--------加入退出--------//

//--------四季变换--------//
/**
 * 通过变化grass和leaf，实现四季变换
 * 
 * @param {number} seconds 一个季节的时间，单位秒
 */
global.seasonChange = async function (seconds) {
    const seasons = ['春', '夏', '秋', '冬'];
    const SpringLeaf = 'green_leaf'; const SummerLeaf = 'leaf_05'; const FallLeaf = 'leaf_03'; const WinterLeaf = 'winter_leaf'
    const grass = ['grass', 'dark_grass', 'yellow_grass', 'white_grass']
    async function replaceBlock(a, b) { for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { for (z = 0; z < 256; z++) { if (voxels.getVoxel(x, y, z) == voxels.id(a)) { voxels.setVoxel(x, y, z, voxels.id(b)) } } } } }
    const time = seconds * 1000;
    (async function changeSeason() {
        while (true) {
            replaceBlock(WinterLeaf, SpringLeaf); replaceBlock(grass[3], grass[0]); world.say(seasons[0] + '天到了');
            await sleep(time);
            replaceBlock(SpringLeaf, SummerLeaf); replaceBlock(grass[0], grass[1]); world.say(seasons[1] + '天到了');
            await sleep(time);
            replaceBlock(SummerLeaf, FallLeaf); replaceBlock(grass[1], grass[2]); world.say(seasons[2] + '天到了');
            await sleep(time);
            replaceBlock(FallLeaf, WinterLeaf); replaceBlock(grass[2], grass[3]); world.say(seasons[3] + '天到了');
            await sleep(time)
        }
    })();
}
//--------四季变换--------//

//--------游戏内光照与现实时间对应--------//


function getBeijingTimeParts() {
    const now = new Date();
    const beijingTimestamp = now.getTime() + 8 * 60 * 60 * 1000; // 转换为北京时间的时间戳
    const beijingDate = new Date(beijingTimestamp);
    return {
        hours: beijingDate.getUTCHours(),
        minutes: beijingDate.getUTCMinutes(),
        seconds: beijingDate.getUTCSeconds(),
        milliseconds: beijingDate.getUTCMilliseconds(),
    };
}

function calculateSunPhase() {
    const parts = getBeijingTimeParts();
    // 计算总小时数（含小数部分）
    const totalHours = parts.hours +
        parts.minutes / 60 +
        parts.seconds / 3600 +
        parts.milliseconds / (3600 * 1000);

    // 计算相对于06:00的时间差
    const delta = (totalHours - 6 + 24) % 24;
    const sunPhase = delta / 24;

    return sunPhase >= 1 ? 0 : sunPhase; // 确保在06:00时返回0
}
global.sunPhaseClock = async function () {
    const phase = calculateSunPhase();
    world.sunPhase = phase;
    console.log(`SunPhase: ${phase.toFixed(8)}`); // 输出此时sunPhase的值并保留8位小数
}
//--------游戏内光照与现实时间对应--------//

//--------自动复活--------//
/**
 * 玩家死亡时，自动复活
 * 
 * @param {number} seconds 复活倒计时，单位秒
 * @param {string} [message] 复活倒计时提示消息(默认：${lessTime}秒后复活......)
 * @param {boolean} [isBroadcast] 是否广播复活倒计时(默认：true)
 */
global.autoRespawn = async function (seconds, { message, isBroadcast }) {
    world.onDie(async ({ entity }) => {
        if (isBroadcast || message) {
            for (let lessTime = seconds; lessTime > 0; lessTime--) {
                await sleep(1000);
                if (message) {
                    entity.player.directMessage(`${lessTime}${message}`);
                } else {
                    entity.player.directMessage(`${lessTime}秒后复活......`)
                }
            }
        }
        entity.player.forceRespawn();
    })
}
//--------自动复活--------//
